跳到主要内容

Golang 项目结构学习

标准项目结构

kit 被不同应用项目导入的基础包 cmd 支持编译不同二进制程序的包,比如 Restful 路由程序,需要相关 router, handler 包和 main 入口包。 internal 项目内部使用的包,包括 crud, service(facade) 和业务逻辑的包。 internal/pkg 为本项目内部使用的基础包,包括数据库、认证和序列化等操作的包。 pkg 其他项目可以访问 pkg 的代码包

Example

示例:

paper-code/examples/groupevent
├── cmd/
│ └── eventtimer/
│ └── update/
│ └── main.go
│ └── eventserver/
│ └── router/
│ └── handler/
│ └── router.go
│ └── tests/
│ └── main.go
├── internal/
│ └── eventserver/
│ └── biz/
│ └── event/
│ └── member/
│ └── data/
│ └── service/
│ └── eventpopdserver/
│ └── event/
│ └── member/
│ └── pkg/
│ └── cfg/
│ └── db/
│ └── log/
└── vendor/ ...
├── go.mod
├── go.sum

/cmd

该目录用于存放 Go 项目的入口,即 main.go。一般来说,我们应该在 cmd 目录下创建子目录,子目录名称代表可执行程序的名称(例如 /cmd/myapp)。

这些代码和业务没有关系。每个程序对应一个文件夹,文件夹的名称应该以程序的名称命名。一般在名称后面加上 d 代表该程序是一个守护进程运行。 每个文件夹必须有一个 main 包的源文件,该源文件的名称也最好命名成可执行程序的名称,当然也可以保留 main 文件名。在此会导入和调用 internal/pkg/ 等其他文件夹中相关的代码。

一般来说,该目录中的代码应该尽可能少。如果认为该代码可以导入并在其他项目中使用,那么它应该位于 /pkg 目录中。如果该代码不可重用,或者不希望其他人重用它,则将该代码放在 /internal 目录中。

/internal

这是 Go 包的一个特性,放在该包中的代码,表明只希望项目内部使用,是项目或库私有的,其他项目或库不能使用。请注意,不限于顶层 internal 目录,internal 在项目树的任何级别上都可以有多个目录

可以选择向内部包中添加一些额外的结构,以分隔共享和非共享内部代码。它不是必需的(尤其是对于较小的项目),但是最好有视觉提示来显示包的用途。

实际应用程序代码可以进入 /internal/app 目录(例如 /internal/app/myapp),而这些应用程序共享的代码可以进入 /internal/pkg 目录(例如 /internal/pkg/myprivlib)。

如果你在其他项目中导入另一个项目的 internal 的代码包,保存或 go build 编译时会报错 use of internal package ... not allowed,该特性是在 go 1.4 版本开始支持的,编译时强行校验。

package main

import (
"paper-code/examples/groupevent/cmd/eventserver/router/handler"
"paper-code/examples/groupevent/cmd/internal"
"paper-code/examples/groupevent/internal/eventpopdserver/event"
"paper-code/examples/groupevent/pkg/middleware"
)

func main() {
middleware.HandlerConv(nil)
event.EventsBy("")
eh := new(handler.EventHandler)
eh.Events(nil, nil)
internal.CmdInternalFunc()
}

如上引用了 internal 包的内容

第 6 行的导入就会提示 use of internal package paper-code/examples/groupevent/internal/eventpopdserver/event not allowed

/pkg

该包可以和 internal 对应,是公开的。一般来说,放在该包的代码应该和具体业务无关,方便本项目和其他项目重用(例如一些通用工具)。当你决定将代码放入该包时,你应该对其负责,因为别人很可能使用它。

如果你把代码包放在根目录的 pkg 下,其他项目是可以直接导入 pkg 下的代码包的,即这里的代码包是开放的,当然你的项目本身也可以直接访问的。

但是如果要把代码放在 pkg 下,还想需要三思而后行吧,有没必要这样做,毕竟 internal 目录是最好的方式保护你的代码并且被 go 编译器强制校验 internal 的代码包不可分享的。

如果项目是一个开源的并且让其他人使用你封装的一些函数等,这样做是合适的,如果你自己或公司的某一个项目,个人的经验,基本上用不上pkg

/vendor

应用程序依存关系,GO1.13启用 go module 来代替,并不需要 vendor 目录了。

服务应用程序目录

/api:OpenAPI/Swagger 规范,JSON 模式文件,协议定义文件。示例

Web 应用程序目录

/web:特定于 Web 应用程序的组件:静态 Web 资产、服务器端模板和 SPAs。

通用应用目录

/configs:配置文件模板或默认配置。

/init:存放随着系统自动启动脚本,如:systemd, upstart, sysv;或者通过 supervisor 进行进程管理的脚本。

/scripts:存放 build、install、analysis 等操作脚本。这些脚本使得项目根目录的 Makefile 很简洁。

/build:该目录用于存放打包和持续集成相关脚本。将云(AMI),容器(Docker),操作系统(deb,rpm,pkg)软件包配置和脚本放在 /build/package 目录中。将CI(travis,circle,drone)配置和脚本放在 /build/ci 目录中。请注意,某些配置项工具(例如Travis CI)对于其配置文件的位置非常挑剔。尝试将配置文件放在 /build/ci 目录中,将它们链接到 CI 工具期望它们的位置。

/deployments:IaaS,PaaS,系统和容器编排部署配置和模板(docker-compose,kubernetes / helm,mesos,terraform,bosh)。

/test:一般用来存放除单元测试、基准测试之外的测试,比如集成测试、测试数据等。